#include <typeinfo>
#include <iostream>

#include <cubefs/core/types.hpp>

using namespace std;
using cubefs::NullType;

template <typename NameType, typename BaseType = NullType>
struct Profile: public BaseType {
    typedef NameType Name;
    typedef BaseType Base;
};

class RootProfileName               {};
class FirstDerivedProfileName       {};
class SecondDerivedProfileName      {};
class ThirdDerivedProfileName        {};

typedef Profile<RootProfileName>                                                RootProfile;
typedef Profile<FirstDerivedProfileName,  RootProfile>                          FirstDerivedProfile;
typedef Profile<SecondDerivedProfileName, RootProfile>                          SecondDerivedProfile;
typedef Profile<ThirdDerivedProfileName,  RootProfile>                          ThirdDerivedProfile;



template <typename TypeType>
struct LocatableBase {
    typedef TypeType Type;
};

class TypeNotFound;

template <typename TargetProfile, typename Default = TypeNotFound>
struct Locatable: public LocatableBase<
            typename Locatable <
                typename TargetProfile::Base,
                Default
            >::Type
> {};

template <typename Default>
struct Locatable<NullType, Default>: public LocatableBase<Default> {};


template <typename Default>
struct Locatable<RootProfile, Default>:
        public LocatableBase<Locatable<RootProfile, Default> > {

    static void dump() {
        cout<<"RootProfile"<<endl;
    }
};

template <typename Default>
struct Locatable<FirstDerivedProfile, Default>:
        public LocatableBase<Locatable<FirstDerivedProfile, Default> > {

    static void dump() {
        cout<<"FirstDerivedProfile"<<endl;
    }
};


template <typename Default>
struct Locatable<SecondDerivedProfile, Default>:
        public LocatableBase<Locatable<SecondDerivedProfile, Default> > {

    static void dump() {
        cout<<"SecondDerivedProfile"<<endl;
    }
};

int main() {

    Locatable<FirstDerivedProfile>::Type  ::dump();
    Locatable<SecondDerivedProfile>::Type ::dump();
    Locatable<ThirdDerivedProfile>::Type  ::dump(); //should print 'RootProfile'

    return 0;
}
